<template>
	<div
		:class="['v-progress', 'v-progress--' + type, status ? 'is-' + status : '']"
	>
		<div class="v-progress-bar" v-if="type === 'line'">
			<div
				class="v-progress-bar__outer"
				:style="{ height: strokeWidth + 'px' }"
			>
				<div class="v-progress-bar__inner" :style="barStyle">
					<div class="v-progress-bar__innerText" v-if="showText && textInside">
						{{ content }}
					</div>
				</div>
			</div>
		</div>
		<div
			class="v-progress-circle"
			:style="{ height: width + 'px', width: width + 'px' }"
			v-else
		>
			<svg viewBox="0 0 100 100">
				<path
					class="v-progress-circle__track"
					:d="trackPath"
					stroke="#e5e9f2"
					:stroke-width="relativeStrokeWidth"
					fill="none"
					:style="trailPathStyle"
				></path>
				<path
					class="v-progress-circle__path"
					:d="trackPath"
					:stroke="stroke"
					fill="none"
					:stroke-linecap="strokeLinecap"
					:stroke-width="percentage ? relativeStrokeWidth : 0"
					:style="circlePathStyle"
				></path>
			</svg>
		</div>
		<div class="v-progress__text" v-if="showText && !textInside">
			<template v-if="!status">{{ content }}</template>
			<!-- <i v-else :class="iconClass"></i> -->
			<slot v-else>{{ content }}</slot>
		</div>
	</div>
</template>
<script>
export default {
	data() {
		return {};
	},
	props: {
		type: {
			type: String,
			default: "line",
			validator: (val) => ["line", "circle", "dashboard"].indexOf(val) > -1,
		},
		percentage: {
			type: Number,
			default: 0,
			required: true,
			validator: (val) => val >= 0 && val <= 100,
		},
		status: {
			type: String,
			validator: (val) => ["success", "exception", "warning"].indexOf(val) > -1,
		},
		strokeWidth: {
			type: Number,
			default: 6,
		},
		strokeLinecap: {
			type: String,
			default: "round",
		},
		textInside: {
			type: Boolean,
			default: false,
		},
		width: {
			type: Number,
			default: 126,
		},
		showText: {
			type: Boolean,
			default: true,
		},
		color: {
			type: [String, Array, Function],
			default: "",
		},
		format: Function,
	},
	computed: {
		barStyle() {
			const style = {};
			style.width = this.percentage + "%";
			style.backgroundColor = this.getCurrentColor(this.percentage);
			return style;
		},
		relativeStrokeWidth() {
			return ((this.strokeWidth / this.width) * 100).toFixed(1);
		},
		radius() {
			if (this.type === "circle" || this.type === "dashboard") {
				return parseInt(50 - parseFloat(this.relativeStrokeWidth) / 2, 10);
			} else {
				return 0;
			}
		},
		content() {
			if (typeof this.format === "function") {
				return this.format(this.percentage) || "";
			} else {
				return `${this.percentage}%`;
			}
		},
		trackPath() {
			const radius = this.radius;
			const isDashboard = this.type === "dashboard";
			return `
          M 50 50
          m 0 ${isDashboard ? "" : "-"}${radius}
          a ${radius} ${radius} 0 1 1 0 ${isDashboard ? "-" : ""}${radius * 2}
          a ${radius} ${radius} 0 1 1 0 ${isDashboard ? "" : "-"}${radius * 2}
          `;
		},
		circlePathStyle() {
			return {
				strokeDasharray: `${
					this.perimeter * this.rate * (this.percentage / 100)
				}px, ${this.perimeter}px`,
				strokeDashoffset: this.strokeDashoffset,
				transition: "stroke-dasharray 0.6s ease 0s, stroke 0.6s ease",
			};
		},
		perimeter() {
			return 2 * Math.PI * this.radius;
		},
		rate() {
			return this.type === "dashboard" ? 0.75 : 1;
		},
		strokeDashoffset() {
			const offset = (-1 * this.perimeter * (1 - this.rate)) / 2;
			return `${offset}px`;
		},
		trailPathStyle() {
			return {
				strokeDasharray: `${this.perimeter * this.rate}px, ${this.perimeter}px`,
				strokeDashoffset: this.strokeDashoffset,
			};
		},
		stroke() {
			let ret;
			if (this.color) {
				ret = this.getCurrentColor(this.percentage);
			} else {
				switch (this.status) {
					case "success":
						ret = "#13ce66";
						break;
					case "exception":
						ret = "#ff4949";
						break;
					case "warning":
						ret = "#e6a23c";
						break;
					default:
						ret = "#ff5858";
				}
			}
			return ret;
		},
	},
	created() {},
	methods: {
		getCurrentColor(percentage) {
			if (typeof this.color === "function") {
				return this.color(percentage);
			} else if (typeof this.color === "string") {
				return this.color;
			}
		},
	},
};
</script>
<style lang="less" scoped>
.v-progress {
	position: relative;
	display: inline-block;
	&.v-progress--line {
		width: 350px;
		.v-progress__text {
			display: inline-block;
			vertical-align: middle;
		}
	}
	.v-progress-bar {
		padding-right: 51px;
		margin-right: -40px;
		display: inline-block;
		vertical-align: middle;
		width: 100%;
		box-sizing: border-box;
		.v-progress-bar__outer {
			height: 6px;
			border-radius: 100px;
			background: #ebeef5;
		}
		.v-progress-bar__inner {
			position: relative;
			border-radius: 100px;
			height: 100%;
			text-align: right;
			background: #ff5858;
			.v-progress-bar__innerText {
				position: absolute;
				top: 50%;
				right: 5px;
				font-size: 12px;
				color: #fff;
				transform: translateY(-50%);
			}
		}
	}
	&.is-success .v-progress-bar__inner {
		background-color: #13ce66;
	}
	&.is-warning .v-progress-bar__inner {
		background-color: #e6a23c;
	}
	&.is-exception .v-progress-bar__inner {
		background-color: #ff4949;
	}
	&.v-progress--circle,
	&.v-progress--dashboard {
		.v-progress__text {
			position: absolute;
			top: 50%;
			left: 0;
			width: 100%;
			text-align: center;
			transform: translateY(-50%);
		}
	}
}
</style>
